package gomysql

import (
	"context"
	"database/sql"
	"fmt"
	"time"

	"github.com/sirupsen/logrus"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"gorm.io/gorm/schema"
)

type GormLogger struct {
	*logrus.Logger
}

func (l *GormLogger) LogMode(level logger.LogLevel) logger.Interface {
	newlogger := *l // make a copy
	switch level {
	case logger.Silent:
		newlogger.SetLevel(logrus.PanicLevel)
	case logger.Error:
		newlogger.SetLevel(logrus.ErrorLevel)
	case logger.Warn:
		newlogger.SetLevel(logrus.WarnLevel)
	case logger.Info:
		newlogger.SetLevel(logrus.InfoLevel)
	default:
		newlogger.SetLevel(logrus.DebugLevel)
	}
	return &newlogger
}

func (l *GormLogger) Info(ctx context.Context, msg string, data ...interface{}) {
	l.WithContext(ctx).WithField("trace_id", ctx.Value("trace_id")).Infof(msg, data...)
}

func (l *GormLogger) Warn(ctx context.Context, msg string, data ...interface{}) {
	l.WithContext(ctx).WithField("trace_id", ctx.Value("trace_id")).Warnf(msg, data...)
}

func (l *GormLogger) Error(ctx context.Context, msg string, data ...interface{}) {
	l.WithContext(ctx).WithField("trace_id", ctx.Value("trace_id")).Errorf(msg, data...)
}

func (l *GormLogger) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) {
	elapsed := time.Since(begin)
	sql, rows := fc()
	traceID := ctx.Value("trace_id")
	if err != nil {
		l.WithFields(logrus.Fields{
			"type":     "mysql",
			"error":    err,
			"elapsed":  elapsed,
			"rows":     rows,
			"sql":      sql,
			"trace_id": traceID,
		}).Error("trace")
	} else {
		l.WithFields(logrus.Fields{
			"type":     "mysql",
			"elapsed":  elapsed,
			"rows":     rows,
			"sql":      sql,
			"trace_id": traceID,
		}).Info("trace")
	}
}

// dbConn 数据库连接信息
var dbConn = make(map[string]*gorm.DB)

// Conn 数据库连接信息
type Conn struct {
	ConfName string
	Host     string
	Port     string
	User     string
	Pwd      string
	Database string
	Prefix   string
}

//NewClient 创建数据库链接
func NewClient(conf *Conn, logger *logrus.Logger) (*gorm.DB, error) {
	if dbConn[conf.ConfName] != nil {
		return dbConn[conf.ConfName], nil
	}
	dns := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=True&loc=Local", conf.User, conf.Pwd, conf.Host, conf.Port, conf.Database)
	sqlDB, _ := sql.Open("mysql", dns)
	sqlDB.SetMaxIdleConns(10)
	sqlDB.SetMaxOpenConns(100)
	sqlDB.SetConnMaxLifetime(time.Hour)
	db, err := gorm.Open(mysql.New(mysql.Config{
		Conn: sqlDB,
	}), &gorm.Config{
		NamingStrategy: schema.NamingStrategy{
			TablePrefix: conf.Prefix,
		},
		Logger: &GormLogger{
			Logger: logger,
		},
	})
	if err != nil {
		fmt.Println(err.Error())
		return nil, err
	}
	dbConn[conf.ConfName] = db
	return dbConn[conf.ConfName], nil
}

// Close 关闭数据库连接
func Close() {
	for k, db := range dbConn {
		sqlDB, _ := db.DB()
		err := sqlDB.Close()
		fmt.Println("关闭数据库连接", k)
		if err != nil {
			fmt.Println("关闭数据库连接失败", k, err.Error())

		} else {
			fmt.Println("关闭数据库连接成功", k)
		}
	}
}
